package com.baizhi.shane.sys.service.impl;

import com.baizhi.shane.constant.SysMapping;
import com.baizhi.shane.sys.dto.SysDivisionLevelDTO;
import com.baizhi.shane.sys.enums.SysDivisionLevelEnum;
import com.baizhi.shane.sys.manager.RedisManager;
import com.baizhi.shane.sys.vo.DivisionLevelVO;
import com.baizhi.shane.sys.vo.SysDivisionTreeVO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baizhi.shane.sys.entity.SysDivision;
import com.baizhi.shane.sys.service.SysDivisionService;
import com.baizhi.shane.sys.mapper.SysDivisionMapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
* @author wbz12
* @description 针对表【sys_division(行政区划表)】的数据库操作Service实现
* @createDate 2023-07-25 22:58:14
*/
@Service
@Slf4j
public class SysDivisionServiceImpl extends ServiceImpl<SysDivisionMapper, SysDivision>
    implements SysDivisionService{

    @Resource
    private RedisManager redisManager;

    /**
     * 获取行政区划级别信息
     *
     * @Author 闻柏智
     * @Date 18:04 2023/7/29
     * @Param
     * @return java.util.List<com.baizhi.shane.sys.enums.SysDivisionLevelEnum>
     **/
    @Override
    public List<SysDivisionLevelDTO> getDivisionLevelInfo() {
        ArrayList<SysDivisionLevelDTO> sysDivisionLevelDTOList = new ArrayList<>();

        SysDivisionLevelDTO provincial = new SysDivisionLevelDTO();
        SysDivisionLevelDTO muncipal = new SysDivisionLevelDTO();
        SysDivisionLevelDTO district = new SysDivisionLevelDTO();

        provincial.setLevel(SysDivisionLevelEnum.PROVINCIAL.getLevel());
        provincial.setLevelName(SysDivisionLevelEnum.PROVINCIAL.getLevelName());
        provincial.setLevelNameEn(SysDivisionLevelEnum.PROVINCIAL.getLevelNameEn());

        muncipal.setLevel(SysDivisionLevelEnum.MUNICIPAL.getLevel());
        muncipal.setLevelName(SysDivisionLevelEnum.MUNICIPAL.getLevelName());
        muncipal.setLevelNameEn(SysDivisionLevelEnum.MUNICIPAL.getLevelNameEn());

        district.setLevel(SysDivisionLevelEnum.DISTRICT.getLevel());
        district.setLevelName(SysDivisionLevelEnum.DISTRICT.getLevelName());
        district.setLevelNameEn(SysDivisionLevelEnum.DISTRICT.getLevelNameEn());

        sysDivisionLevelDTOList.add(provincial);
        sysDivisionLevelDTOList.add(muncipal);
        sysDivisionLevelDTOList.add(district);

        return sysDivisionLevelDTOList;
    }

    /**
     * 获取指定等级的行政区划列表
     *
     * @Author 闻柏智
     * @Date 17:10 2023/7/30
     * @Param divisionLevelVO
     * @return java.util.List<com.baizhi.shane.sys.entity.SysDivision>
     **/
    @Override
    public List<SysDivision> getDivisionListByLevel(DivisionLevelVO divisionLevelVO) {
        Integer divisionLevel = divisionLevelVO.getDivisionLevel();
        LambdaQueryWrapper<SysDivision> qwSd = new LambdaQueryWrapper<>();
        qwSd.eq(SysDivision::getDelFlag,0);
        qwSd.eq(SysDivision::getDivisionLevel,divisionLevel);
        if (divisionLevelVO.getParentId() != null) {
            qwSd.eq(SysDivision::getParentId,divisionLevelVO.getParentId());
        }
        List<SysDivision> sysDivisionList = this.list(qwSd);
        return sysDivisionList;
    }

    @Override
    public List<SysDivisionTreeVO> getDivisionTreeByLevel() {
        // 从缓存中获取行政区划树形结构
        Object redisTreeObj = redisManager.get(SysMapping.DIVISION_TREE);
        // 创建jackson转换工具对象
        ObjectMapper objectMapper = new ObjectMapper();
        /* 若缓存中有数据，则用缓存的 */
        if (redisTreeObj != null) {

            String redisTreeString = (String) redisTreeObj;
            List<SysDivisionTreeVO> redisTreeVOList = new ArrayList<>();
            try {
                redisTreeVOList = objectMapper.readValue(redisTreeString, List.class);
            } catch (JsonProcessingException e) {
                throw new RuntimeException(e);
            }
            return redisTreeVOList;
        }

        /* 代码到此证明缓存中无数据，因此从MySQL中查 */

        // 获取所有的数据
        List<SysDivision> sysDivisionList = this.list();
        /* 转化为VO列表 */
        List<SysDivisionTreeVO> sysDivisionTreeVOList = new ArrayList<>();
        for (SysDivision sysDivision : sysDivisionList) {
            SysDivisionTreeVO sysDivisionTreeVO = new SysDivisionTreeVO();
            BeanUtils.copyProperties(sysDivision, sysDivisionTreeVO);
            sysDivisionTreeVOList.add(sysDivisionTreeVO);
        }
        // 转为树
        List<SysDivisionTreeVO> resultList = this.buildTree(sysDivisionTreeVOList);
        /* 存入缓存 */
        // 先设置value的初始值为null
        String redisTreeString = null;
        try {
            // 列表对象转为value
            redisTreeString = objectMapper.writeValueAsString(resultList);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
        // 放入Redis
        redisManager.set(SysMapping.DIVISION_TREE, redisTreeString);
        return resultList;
    }

    public List<SysDivisionTreeVO> buildTree(List<SysDivisionTreeVO> nodeList) {
        List<SysDivisionTreeVO> tree = new ArrayList<>();

        // 创建一个映射表，将节点的id作为key，节点本身作为value
        Map<Long, SysDivisionTreeVO> nodeMap = new HashMap<>();
        for (SysDivisionTreeVO node : nodeList) {
            nodeMap.put(node.getId(), node);
        }

        // 遍历节点列表，构建树形结构
        for (SysDivisionTreeVO node : nodeList) {
            Long parentId = node.getParentId();
            if (parentId == null) {
                // 如果当前节点的parentId为null，说明它是根节点
                tree.add(node);
            } else {
                // 如果当前节点有父节点
                SysDivisionTreeVO parent = nodeMap.get(parentId);
                if (parent != null) {
                    if (parent.getChildren() == null) {
                        // 如果父节点的children属性为null，需要初始化为一个空列表
                        parent.setChildren(new ArrayList<>());
                    }
                    // 将当前节点添加到父节点的children列表中
                    parent.getChildren().add(node);
                }
            }
        }


        return tree;
    }
}




